package com.ansion.utils.thread;

import com.ansion.log.VLog;

import java.util.concurrent.atomic.AtomicLong;

/**
 * 所有子类方法中, 如果有exception风险的,都必须加try catch, 否则会catch到这里造成不可逆转的bug.
 */
public abstract class AbstractRefreshUIThread extends Thread {

    private static String TAG = AbstractRefreshUIThread.class.getSimpleName();

    private final AtomicLong mLastRefreshTime = new AtomicLong(0);

    private boolean mIsStillAlive = false;

    /**
     * millseconds
     */
    private int refreshInterval = 1000;
    
    protected abstract boolean loadUIData(); // return whether it is OK to wait

    @Override
    public void run() {
        long lastUpdateTime;
        synchronized (mLastRefreshTime) {
            lastUpdateTime = mLastRefreshTime.get();
        }

        long lastWaited = -1;
        while (mIsStillAlive) {
            try {
                boolean ok2Wait = true;
                try {
                    VLog.d(TAG, "AbstractRefreshUIThread run IN WHILE loadUIData");
                    ok2Wait = loadUIData();
                } catch (Exception e) {
                    VLog.e(TAG, e);
                }

                if (ok2Wait) {
                    sleep(refreshInterval);
                    synchronized (mLastRefreshTime) {
                        if (lastUpdateTime == mLastRefreshTime.get()) {
                            if (lastWaited <= 0 || System.currentTimeMillis() - lastWaited > 300000) { // 5 minutes later
                                mLastRefreshTime.wait();
                            } else {
                                mLastRefreshTime.wait(refreshInterval * 3);
                            }
                        }
                        lastUpdateTime = mLastRefreshTime.get();
                    }
                } else {
                    lastWaited = System.currentTimeMillis();
                    sleep(refreshInterval * 3); // wait 3s, so user should have accept or refuse read contacts permission
                }

                if (!mIsStillAlive) {
                    break;
                }
            } catch (Throwable e) { // 使用throwable，且循环结束后mIsStillAlive赋值false，以避免线程在ERROR时挂掉，且不再重新启动
                try {
                    sleep(refreshInterval);
                } catch (InterruptedException e1) {
                    VLog.eonly(e1);
                }
            }
        }

        mIsStillAlive = false;
    }

    public void setRefreshInterval(int ms) {
        refreshInterval = ms;
    }

	public synchronized void startQuery() {
		notifyQuery(false);
	}

    /**
     * Never forget to destroy this.
     */
    public synchronized void destroy() {
        mIsStillAlive = false;
        notifyQuery(true);
    }

    protected void notifyQuery(boolean exit) {
		if (!exit && !mIsStillAlive) {
			mIsStillAlive = true;
			try {
                VLog.d(TAG, "notifyQuery strt thread");
				start();
			} catch (Throwable e) {

			}
		}

        synchronized (mLastRefreshTime) {
            long now = System.currentTimeMillis();
            mLastRefreshTime.set(now);
            VLog.d(TAG, "notify thread to continue run");
            mLastRefreshTime.notify();
        }
    }
}
